#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <wait.h>
#include <string.h>

#define HISTORYNUM 10
#define MAX_LINE 80
struct Queue {
    char history[HISTORYNUM][MAX_LINE];
    int front;
    int rear;
} queue;

void add(char *str) { //添加命令进history，这里用循环队列实现
    if (queue.front == -1) {
        strcpy(queue.history[queue.rear], str);
        queue.front = queue.rear;
        return;
    }

    queue.rear = (queue.rear + 1) % HISTORYNUM;
    strcpy(queue.history[queue.rear], str);
    if (queue.front == queue.rear) queue.front = (queue.front + 1) % HISTORYNUM;
}

//打印历史命令
void print() {
    if (queue.front == -1) {//空队列，无历史命令
        printf("No command!");
        return;
    }
    int index = queue.front;
    printf("\n");
    fflush(stdout);
    printf("%s\n", queue.history[index]); //先输出第一个历史命令，否则循环队列将无意义，当超出历史命令条数时，循环无法进入
    fflush(stdout);
    index = (index + 1) % HISTORYNUM;
    while (index != (queue.rear + 1) && (!(index == 0 && queue.rear == 9))) { //后面一个条件是防止这种情况进入死循环，因为，index永远不可能等于10
        printf("%s\n", queue.history[index]);
        fflush(stdout);
        index = (index + 1) % HISTORYNUM;
    }
}

char *gethistory(char c) { //得到以‘x'开头的命令

    int temp = queue.front;
    while (temp != queue.rear + 1) {
        if (queue.history[temp][0] == c)return queue.history[temp];//找到就退出
        temp = (temp + 1) % HISTORYNUM;
    }
    if (temp == queue.rear + 1) return NULL; //搜索完一遍还是没有，就返回NULL

    return NULL;
}

char *getnearhistory() { //返回最近的历史命令
    if (queue.front == -1) return NULL; //无历史命令
    else return queue.history[queue.rear];
}

//int getNum() {  //得到历史命令的数目
//    return (queue.rear + HISTORYNUM - queue.front + 1) % HISTORYNUM;
//}


void setup(char *inputBuffer, char *args[], int *background) {
    int length;//命令的字符数目
    int start;//命令的第一个字符位置
    int ct; //下一个参数存入args[]的位置
    ct = 0;

    //读入命令行字符串，存入inputBuffer
    length = read(STDIN_FILENO, inputBuffer, MAX_LINE);
    start = -1;
    if (length == 0)exit(0);
    else if (length < 0) { //ctrl +c
        perror("error reading the command");
        args[0] = NULL;
        return;
    }

    /*用户通过输入"rx" 可以运行之前10 个命令中的任何一个，
    其中"x" 为该命令的第一个字母。如果有个命令以"x" 开头，则执行最近的一个。同样，
    用户可以通过仅输入"r"来再次运行最近的命令*/
    char *str;
    if (inputBuffer[0] == 'r') {
        if (inputBuffer[0] == 'r' && inputBuffer[1] == '\n') { //当只有'r'
            str = getnearhistory();
            if (str == NULL) { //取最近的一条命令，如果没有命令则返回NULL
                perror("no nearhistory input command!");
                return;
            } else strcpy(inputBuffer, str);
        } else if (inputBuffer[3] == '\n' || inputBuffer[3] == '\t') {
            str = gethistory(inputBuffer[2]);
            //if((str=gethistory(inputBuffer[2])==NULL))
            if (str == NULL) { //如果没有以x开头的命令，会返回null
                perror("No input command!");
                return;
            } else strcpy(inputBuffer, str); //放入inputBuffer来执行
        }

        inputBuffer[strlen(str)] = '\n';//以便下面代码统一读取
        inputBuffer[strlen(str) + 1] = '\0';//结束符
        length = strlen(str) + 1;
    }
    int i;
    //检查inputBuffer中每一个字符
    for (i = 0; i < length; i++) {
        switch (inputBuffer[i]) {
            case ' ':
            case '\t'://字符为参数的空格或者tab
                if (start != -1) {
                    args[ct] = &inputBuffer[start];
                    ct++;
                }
                inputBuffer[i] = '\0';//设置c string的结束符
                start = -1;
                break;

            case '\n'://命令行结束符
                if (start != -1) {
                    args[ct] = &inputBuffer[start];
                    ct++;
                }
                inputBuffer[i] = '\0';
                args[ct] = NULL;
                break;
            case '&':
                *background = 1;
                inputBuffer[i] = '\0';
                break;
            default://其他字符
                if (start == -1) start = i;

        }
    }
    add(inputBuffer);//增加历史记录
    args[ct] = NULL;//命令字符数>80
}

void handle_SIGINT() {
    printf("\nCOMMAND HISTORY:");
    print(); //打印历史命令
    signal(SIGINT, SIG_IGN);
}

int main(void) {
    char inputBuffer[MAX_LINE];//这个缓存用来存放输入的命令
    int background;// == 1时，表示在后台运行命令
    char *args[MAX_LINE / 2 + 1];//命令最多40个参数
    pid_t pid;
    struct sigaction hander;

    queue.front = -1;
    queue.rear = 0;

    while (1) {//程序在setup中正常结束
        background = 0;
        printf("COMMAND->");

        fflush(stdout);//输出
        setup(inputBuffer, args, &background);

        //这一步要创建子进程
        if ((pid = fork()) == -1) { printf("Fork Error.\n"); }//创建失败
        if (pid == 0) {
            execvp(args[0], args);
            exit(0);
        }//子进程
        if (background == 0) { wait(0); } //如果background为1，表示在后台运行，则父进程不用等子进程执行完，否则要wait

        /**
        *创建信号处理器，处理ctrl+c,+z等信号
        */
        hander.sa_handler = (void (*)(int)) handle_SIGINT;
        sigaction(SIGINT, &hander, NULL);

        /**
        *循环运行，直到收到ctrl+c获ctrl+z等信号
        */
    }
    return 0;
}